package com.heima.search.service.Impl;

import com.alibaba.fastjson.JSON;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.dtos.UserSearchDto;
import com.heima.model.user.pojos.ApUser;
import com.heima.search.service.ApUserSearchService;
import com.heima.search.service.ArticleSearchService;
import com.heima.utils.thread.AppThreadLocalUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
@RequiredArgsConstructor
public class ArticleSearchServiceImpl implements ArticleSearchService {

    private final RestHighLevelClient restHighLevelClient;

    private final ApUserSearchService apUserSearchService;
    /**
     * ES 文章搜索
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult search(UserSearchDto dto) throws Exception {
        //参数校验
        if (dto == null || StringUtils.isBlank(dto.getSearchWords())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //获取用户信息，异步保存搜索记录
        ApUser user = AppThreadLocalUtil.getUser();
        if (user != null && dto.getFromIndex() == 0 ){
            //保存搜索记录
            apUserSearchService.insert(dto.getSearchWords(), user.getId());
        }

        // 创建Elasticsearch查询请求对象，指定目标索引为"app_info_article"
        SearchRequest searchRequest = new SearchRequest("app_info_article");

        // 构建查询参数的构造器，用于配置查询条件、分页、排序等
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        // 使用布尔查询组合多个查询条件（must、should、filter等逻辑）
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        // -------------------------- 关键字搜索（分词查询）--------------------------
        // 在title和content字段中搜索用户输入的关键词（dto.getSearchWords()）
        // 使用OR逻辑，匹配任意一个字段包含关键词即可
        QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders
                .queryStringQuery(dto.getSearchWords()) // 获取用户输入的搜索词
                .field("title")                         // 搜索title字段
                .field("content")                       // 搜索content字段
                .defaultOperator(Operator.OR);          // 设置默认逻辑为OR（匹配任意关键词）

        // 将关键字查询设置为布尔查询的must条件（必须满足）
        boolQueryBuilder.must(queryStringQueryBuilder);

        // -------------------------- 时间范围过滤 --------------------------
        // 过滤publishTime字段满足条件的文档（需补充具体范围条件）
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("publishTime");
        //  注意：此处需补充具体范围条件，例如：
        // rangeQueryBuilder.gte(minDate).lt(maxDate); // 过滤时间在[minDate, maxDate)之间的文档
        boolQueryBuilder.filter(rangeQueryBuilder); // 将范围查询作为过滤条件（不影响评分）

        // -------------------------- 分页配置 --------------------------
        // 设置分页起始位置（从第0条开始，即第一页）
        searchSourceBuilder.from(0);
        // 设置每页显示数量（从分页参数dto中获取）
        searchSourceBuilder.size(dto.getPageSize());

        // -------------------------- 排序配置 --------------------------
        // 按publishTime字段降序排列（最新发布的文章优先）
        searchSourceBuilder.sort("publishTime", SortOrder.DESC);

        // -------------------------- 高亮配置 --------------------------
        // 配置高亮显示，用于在搜索结果中标记匹配的关键词
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        // 对title字段进行高亮
        highlightBuilder.field("title");
        // 扩展：若需高亮content字段，可添加 highlightBuilder.field("content");
        // 设置高亮标签（红色字体包裹匹配文本）
        highlightBuilder.preTags("<font style='color: red; font-size: inherit;'>");
        highlightBuilder.postTags("</font>");
        // 将高亮配置添加到查询参数中
        searchSourceBuilder.highlighter(highlightBuilder);

        // -------------------------- 组合查询条件并执行 --------------------------
        // 将布尔查询设置为最终查询条件
        searchSourceBuilder.query(boolQueryBuilder);
        // 将所有配置参数绑定到查询请求对象
        searchRequest.source(searchSourceBuilder);
        // 执行查询并获取结果
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        //结果封装
        List<Map> list = new ArrayList<>(); // 初始化结果列表

        SearchHit[] hits = searchResponse.getHits().getHits(); // 获取所有匹配的文档
        for (SearchHit hit : hits) {
            String json = hit.getSourceAsString(); // 获取文档的原始JSON数据
            // 若JSON为空，则跳过当前文档
            if (StringUtils.isBlank(json)){
                continue;
            }
            Map map = JSON.parseObject(json, Map.class); // 将JSON转为Map对象

            // 处理高亮字段（title）
            if (hit.getHighlightFields() != null && !hit.getHighlightFields().isEmpty()) {
                // 获取高亮的title片段
                Text[] titles = hit.getHighlightFields().get("title").getFragments();
                String title = StringUtils.join(titles); // 合并高亮片段为字符串
                map.put("h_title", title); // 存储高亮后的标题
            } else {
                // 若无高亮，则使用原始标题
                map.put("h_title", map.get("title"));
            }
            list.add(map); // 将处理后的Map添加到结果列表
        }

        return ResponseResult.okResult(list);
    }
}
